#pragma once

#include "TcpServer.hpp"
#include "Socket.hpp"
#include <memory>
#include <unordered_map>
#include <sstream>
#include <functional>
#include "util.hpp"

using namespace SocketModule;

const std::string gspace = " ";
const std::string glinespace = "\r\n";
const std::string gsep = ": ";
const std::string webroot = "./webroot";
const std::string homepage = "/index.html";

// GET（从远端获取内容） POST（向远端进行参数提交，上传资源）
// 请求行：请求方法 uri（目前是一段路径） http版本
class HttpRequest
{
public:
    HttpRequest()
    {
    }

    std::string Serialize() // 完成构建http协议
    {
        // 序列化为字符串，然后发送出去
        return "";
    }

    void ParseReqLine(std::string &reqline)
    {
        std::stringstream ss(reqline);
        // stringstream的默认分隔符就是空行
        ss >> _method >> _uri >> _version;
    }

    bool Deserialize(std::string &reqstr)
    {
        // 提取出请求行
        std::string req_line;
        bool res = util::ReadOneLine(reqstr, &req_line, gsep);

        // 对请求行进行反序列化
        ParseReqLine(req_line);

        // 对路径进行拼接：
        if (_uri == "/")
        {
            _uri = webroot + _uri + homepage;
        }
        else
        {
            _uri = webroot + _uri;
        }

        const std::string temp = "?";
        auto pos = _uri.find(temp);
        if(pos == std::string::npos)
        {
            _is_interact = false;
            return true;
        }
        _is_interact = true;
        _args = _uri.substr(pos + sizeof(temp));
        _uri = _uri.substr(0, pos);

        return true;
    }

    std::string &Uri()
    {
        return _uri;
    }

    ~HttpRequest()
    {
    }

private:
    std::string _method;
    std::string _uri;
    std::string _version;

    std::unordered_map<std::string, std::string> _headers;
    std::string _blankline = glinespace;
    std::string _text;

    std::string _args;
    bool _is_interact;
};

class HttpResponse
{
public:
    HttpResponse() {}

    // 成熟的http不依赖任何第三方库，自己做序列化
    std::string Serialize()
    {
        // 状态行
        std::string status_line = _version + gspace + std::to_string(_code) + gspace + _desc + glinespace;

        // 响应报头
        std::string resp_header;
        for (auto &header : _headers)
        {
            std::string line = header.first + gsep + header.second;
            resp_header += line;
        }

        return status_line + resp_header + _blankline + _text;
    }

    void SetTargetFile(std::string &target)
    {
        _targetfile = target;
    }

    void SetCode(int code)
    {
        _code = code;
        switch (_code)
        {
        case 200:
            _desc = "OK";
            break;
        case 404:
            _desc = "NotFound";
            break;
        default:
            break;
        }
    }

    void SetHeader(std::string key, std::string value)
    {
        auto iter = _headers.find(key);
        if (iter != _headers.end())
        {
            return;
        }
        _headers.insert(std::make_pair(key, value));
    }

    std::string Uri2Suffix(std::string &targetfile)
    {
        auto pos = targetfile.rfind(".");
        if (pos == std::string::npos)
        {
            return "text/html";
        }
        std::string suffix = targetfile.substr(pos);
        if (suffix == ".html" | suffix == ".htm")
        {
            return "text/html";
        }
        else if (suffix == ".jpg")
        {
            return "image/jpeg";
        }
        else
        {
            return "...";
        }
        //...此处建立各种映射关系
    }

    bool MakeResponse()
    {
        bool res = util::ReadFileContent(_targetfile, &_text);
        if (!res)
        {
            _code = 404;
            _desc = "Not Found";
            SetCode(404);
        }
        else
        {
            SetCode(200);
            int filesize = util::FileSize(_targetfile);
            std::string suffix = Uri2Suffix(_targetfile);
            SetHeader("Content-Type", suffix);
            SetHeader("Cookie", "username=zhangsan; password=123456");
            // SetHeader("Content-Length", std::to_string(filesize));
        }
        return true;
    }

    std::string Deserialize(std::string &reqstr)
    {
        return " ";
    }

    ~HttpResponse() {}

public:
    std::string _version;
    int _code;         // 状态码
    std::string _desc; // 状态码描述 404（状态码） “Not Found”（状态描述）
    std::unordered_map<std::string, std::string> _headers;
    std::vector<std::string> _cookies;

    std::string _blankline = glinespace;
    std::string _text;

    std::string _targetfile; // 其他属性，用于状态码的判断
};

using http_func_t = std::function<void(std::string& request, std::string& response)>;

class Http
{
public:
    Http(uint16_t port)
        : tsvrp(std::make_unique<TcpServer>(port))
    {
    }

    void HandlerHttpRequest(std::unique_ptr<Socket> &sock, InitAddr &client)
    {
        std::string httpreqstr;
        int n = sock->Recv(&httpreqstr);
        if (n > 0)
        {
            // 这里没有对报文的完整性进行审核
            // 给用户返回的图片视频音频都是静态资源
            HttpRequest req;
            req.Deserialize(httpreqstr);
            HttpResponse resp;
            resp.SetTargetFile(req.Uri());

            std::string filename = req.Uri();
            resp._version = "HTTP/1.1";
            resp._code = 200; // 成功
            resp._desc = "OK";

            std::cout << "用户请求:" << filename << std::endl;
            bool res = util::ReadFileContent(filename, &(resp._text));
            std::string resp_str = resp.Serialize();
            sock->Send(resp_str);
        }

        // #ifndef DEBUG
        // #define DEBUG
        // std::string httpreqstr;
        // //不一定能读到完整的报文但是因为空行的存在一定能够知道一个报文的完整的报头
        // //在报头当中存在一种属性——Content-Length,记录的是正文的大小
        // //从空格之后的部分中提取Content-Length
        // sock->Recv(&httpreqstr);
        // std::cout << httpreqstr << std::endl;

        // //构建应答，内存级别+固定
        // HttpResponse resp;
        // resp._version = "HTTP/1.1";
        // resp._code = 200; //成功
        // resp._desc = "OK";
        // std::string filename = webroot + homepage; //返回首页
        // bool res = util::ReadFileContent(filename, &(resp._text));

        // std::string response_str = resp.Serialize(); //将结构化数据转换成大字符串
        // sock->Send(response_str);
        // #endif
    }

    void RegisterService(const std::string& name, http_func_t h)
    {
        std::string key = webroot + name; // ./wwwroot/login
        auto iter = _route.find(name);
        if(iter == _route.end())
        {
            _route.insert(std::make_pair(name, h));
        }
    }

    void Start()
    {
        tsvrp->Start([this](std::unique_ptr<Socket> &sock, InitAddr &client)
                     { this->HandlerHttpRequest(sock, client); });
    }

    ~Http() {}

private:
    std::unique_ptr<TcpServer> tsvrp;
    std::unordered_map<std::string, http_func_t> _route; 
};